--[[
  10.1.13.15:5532 cics 核心 (需要强制指定协议)
]]
require("apm_core")
require("ApmXml")

local G_DEBUG = true

if G_DEBUG == false then
    function logDebug(fmt,...) end
    function logInfo(fmt,...) end
    function logWarn(fmt,...) end
    function logError(fmt,...) end
    function logFatal(fmt,...) end
end

local t_xml_tree
local i_header_len = 59
local s_message_req
local s_message_resp
local s_seq_no
local s_brc
local s_teller
local s_type_name
local s_channel_id
local s_rspcode
local s_rspmsg
local s_acctno          -- 账号/付款人账号
local s_acctno1         -- 收款人账号

local s_acqserstan      -- 受理流水号
local s_billstan        -- 票据流水号
local s_cancelseq       -- 冲正流水号
local s_clearserstan    -- 结消流水号
local s_ptxnseq         -- 主机流水号
local s_recvstan        -- 来帐流水号
local s_sendstan        -- 发送流水号
local s_serseqno        -- 主机流水号
local s_serstan         -- 网点流水号
local s_telseq          -- 柜员流水号
local s_termseq         -- 终端流水号
local s_devstan         -- 终端交易流水号
local s_srvstan         -- 前置机流水号
local s_transeq         -- 交易流水号
local s_collectseqno    -- 交易流水号

local function parseIp(ip)
    local _, _, value = string.find(ip, "(%d+.%d+)$");
    return value == nil and "" or value
end

local function head_parser(s_payload)
    if s_payload == nil then return nil end

    if string.len(s_payload) <= i_header_len then return nil end

    return string.sub(s_payload, i_header_len), string.sub(s_payload, 52, 57)
end

local function message_parser(s_message_body)
    local t = {};
    if s_message_body == nil then return t end

    local i_message_len = string.len(s_message_body)
    if i_message_len == 0 then return t end

    local s_separator = "</>"
    local i_separator_len = string.len(s_separator)
    local i_start = 1
    local s_tmp
    local y
    local s_key, s_value, i_len
    local i = string.find(s_message_body, s_separator, i_start)

    while i ~= nil and i < i_message_len do
        if i_start < i then
            s_tmp = string.sub(s_message_body, i_start, i - 1);
            if s_tmp ~= nil then
                s_tmp = string.trim(s_tmp);
                if string.sub(s_tmp, 0, 1) == "<" then
                    y = string.find(s_tmp, ">")
                    if y > 2 then
                        s_key = string.sub(s_tmp, 2, y - 1)
                        s_value = string.sub(s_tmp, y + 1)
                        t[s_key] = s_value
                    end
                end
            end
        end
        i_start = i + i_separator_len
        i = string.find(s_message_body, s_separator, i_start)
    end

    return t
end

--- 解析请求
-- return
-- true: 解析成功; false: 解析失败
local function parse_request(ApmData, s_message_body, s_tran_code)
    local t_kv = message_parser(s_message_body);

    -- 流水号
    if s_seq_no == nil then s_seq_no = t_kv["SerSeqNo"] end

    if s_acqserstan == nil then s_acqserstan = t_kv["AcqSerStan"] end
    if s_billstan == nil then s_billstan = t_kv["BillStan"] end
    if s_cancelseq == nil then s_cancelseq = t_kv["CancelSeq"] end
    if s_clearserstan == nil then s_clearserstan = t_kv["ClearSerStan"] end
    if s_ptxnseq == nil then s_ptxnseq = t_kv["PtxnSeq"] end
    if s_recvstan == nil then s_recvstan = t_kv["RecvStan"] end
    if s_sendstan == nil then s_sendstan = t_kv["SendStan"] end
    if s_serstan == nil then s_serstan = t_kv["SerStan"] end
    if s_telseq == nil then s_telseq = t_kv["TelSeq"] end
    if s_termseq == nil then s_termseq = t_kv["TermSeq"] end
    if s_devstan == nil then s_devstan = t_kv["DevStan"] end
    if s_srvstan == nil then s_srvstan = t_kv["SrvStan"] end
    if s_collectseqno == nil then s_collectseqno = t_kv["CollectSeqNo"] end

    if s_acctno == nil then s_acctno = t_kv["AcctNo"] end
    if s_acctno1 == nil then s_acctno1 = t_kv["AcctNo1"] end

    -- 机构号
    if s_brc == nil then
        s_brc = t_kv["Brc"]
        ApmData.replaceField("transaction.branch_code", s_brc == nil and "" or string.trim(s_brc))
    end

    -- 柜员号
    if s_teller == nil then
        s_teller = t_kv["Teller"]
        ApmData.replaceField("transaction.teller_code", s_teller == nil and "" or string.trim(s_teller))
    end

    -- 交易名
    if s_type_name == nil then
        s_type_name = t_kv["TranName"]
        ApmData.replaceField("transaction.type_code", s_type_name == nil and "未知" or string.trim(s_type_name))
        ApmData.replaceField("transaction.type_name", s_type_name == nil and "未知" or string.trim(s_type_name))
--        ApmData.replaceField("transaction.title", s_type_name == nil and "未知" or string.trim(s_type_name))
    end

    -- 交易渠道
    if s_channel_id == nil then
        s_channel_id = t_kv["ChannelId"]
        if s_channel_id == nil then
            s_channel_id = "未知"
        else
            local s_channel_id_in_arr = arr_channel_id[s_channel_id];
            if s_channel_id_in_arr == nil then
            else
                s_channel_id = s_channel_id_in_arr
            end
        end
        ApmData.replaceField("transaction.channel_code", s_channel_id)
        ApmData.replaceField("transaction.channel_name", s_channel_id)
    end



    -- 交易号
    --    if s_tran_code ~= nil then
    --        ApmData.replaceField("transaction.code", s_tran_code);
    --    end

    -- 交易类型
    --    local s_trankind = t_kv["TranKind"];
    --    if s_trankind == nil then
    --        s_trankind = t_kv["TransKind"];
    --    end

    --    if s_trankind == nil then
    --        ApmData.replaceField("transaction.type_code", "UNKNOWN");
    --    else
    --        s_trankind = string.trim(s_trankind);
    --        if s_trankind == "" then s_trankind = "UNKNOWN" end
    --        ApmData.replaceField("transaction.type_code", s_trankind);
    --    end

    return true;
end

local arr_channel_id = {}
arr_channel_id["00"] = "主机"
arr_channel_id["01"] = "银联中心atm"
arr_channel_id["02"] = "银联中心cdm"
arr_channel_id["03"] = "银联中心pos"
arr_channel_id["04"] = "银联中心crs存取款一体机"
arr_channel_id["05"] = "银联中心自助查询终端"
arr_channel_id["06"] = "银联中心柜台"
arr_channel_id["07"] = "银联中心网上银行"
arr_channel_id["08"] = "银联中心手机银行"
arr_channel_id["09"] = "银联中心电话银行"
arr_channel_id["10"] = "银联中心圈存圈提设备"
arr_channel_id["11"] = "银联中心移动pos"
arr_channel_id["12"] = "本行柜台"
arr_channel_id["13"] = "本行atm"
arr_channel_id["14"] = "本行pos"
arr_channel_id["15"] = "本行cdm"
arr_channel_id["16"] = "本行电话银行"
arr_channel_id["17"] = "本行网上银行"
arr_channel_id["18"] = "本行手机银行"
arr_channel_id["19"] = "本行自助查询终端"
arr_channel_id["20"] = "本行呼叫中心"
arr_channel_id["21"] = "本行crs存取款一体机"
arr_channel_id["22"] = "银联商务pos"
arr_channel_id["23"] = "建行atm"
arr_channel_id["24"] = "建行pos设备"
arr_channel_id["25"] = "华夏银行atm"
arr_channel_id["26"] = "香港atm"
arr_channel_id["27"] = "澳门atm"
arr_channel_id["28"] = "支付系统"
arr_channel_id["29"] = "本行柜面通"
arr_channel_id["30"] = "国际结算"
arr_channel_id["31"] = "银联数据（贷记卡）"
arr_channel_id["32"] = "香港pos"
arr_channel_id["33"] = "澳门pos"
arr_channel_id["34"] = "欧洲atm"
arr_channel_id["35"] = "欧洲pos"
arr_channel_id["36"] = "新加坡atm"
arr_channel_id["37"] = "新加坡pos"
arr_channel_id["38"] = "泰国atm"
arr_channel_id["39"] = "泰国pos"
arr_channel_id["40"] = "韩国atm"
arr_channel_id["41"] = "韩国pos"
arr_channel_id["42"] = "银联公共服务平台"
arr_channel_id["43"] = "美国atm"
arr_channel_id["44"] = "德国atm"
arr_channel_id["45"] = "法国atm"
arr_channel_id["46"] = "日本atm"
arr_channel_id["47"] = "印度尼西亚atm"
arr_channel_id["48"] = "菲律宾atm"
arr_channel_id["49"] = "越南atm"
arr_channel_id["50"] = "老挝atm"
arr_channel_id["51"] = "美国pos"
arr_channel_id["52"] = "德国pos"
arr_channel_id["53"] = "法国pos"
arr_channel_id["54"] = "日本pos"
arr_channel_id["55"] = "印度尼西亚pos"
arr_channel_id["56"] = "菲律宾pos"
arr_channel_id["57"] = "越南pos"
arr_channel_id["58"] = "老挝pos"
arr_channel_id["64"] = "本行无线pos"
arr_channel_id["65"] = "本行固话pos"
arr_channel_id["66"] = "本行mis"
arr_channel_id["72"] = "银联中心公共服务平台"
arr_channel_id["73"] = "银联中心农民工银行卡特色服务"
arr_channel_id["74"] = "银联中心商户系统"
arr_channel_id["75"] = "银联中心第三方机构系统（目前主要是渠道接入机构）"
arr_channel_id["76"] = "银联中心数字机顶盒"
arr_channel_id["77"] = "银联中心II型固定电话"
arr_channel_id["78"] = "银联中心保留使用"
arr_channel_id["79"] = "银联中心保留使用"
arr_channel_id["80"] = "银联中心批量文件处理系统"
arr_channel_id["81"] = "银联中心Reserved for use"
arr_channel_id["82"] = "银联中心音频刷卡支付终端（VI-POS）"
arr_channel_id["97"] = "中间业务前台"
arr_channel_id["98"] = "中间业务第三方"
arr_channel_id["99"] = "其他"
arr_channel_id["QS"] = "卡清算综合平台"
arr_channel_id["BB"] = "第三方存管业务系统"
arr_channel_id["CB"] = "城商行联盟"
arr_channel_id["T1"] = "电信一卡通"
arr_channel_id["MP"] = "小额支付系统"
arr_channel_id["IM"] = "影像系统"
arr_channel_id["BD"] = "债券"
arr_channel_id["ZL"] = "银联分公司pos转发"
arr_channel_id["A0"] = "其他"


--- 解析响应
-- return
-- true: 解析成功; false: 解析失败
local function parse_response(ApmData, s_message_body, s_tran_code)
    local t_kv = message_parser(s_message_body)

    -- 流水号
    s_seq_no = t_kv["SerSeqNo"]
--    ApmData.replaceField("transaction.seq_no", s_seq_no == nil and "" or string.trim(s_seq_no))

    s_acqserstan = t_kv["AcqSerStan"]
    s_billstan = t_kv["BillStan"]
    s_cancelseq = t_kv["CancelSeq"]
    s_clearserstan = t_kv["ClearSerStan"]
    s_ptxnseq = t_kv["PtxnSeq"]
    s_recvstan = t_kv["RecvStan"]
    s_sendstan = t_kv["SendStan"]
    s_serstan = t_kv["SerStan"]
    s_telseq = t_kv["TelSeq"]
    s_termseq = t_kv["TermSeq"]
    s_devstan = t_kv["DevStan"]
    s_srvstan = t_kv["SrvStan"]
    s_transeq = t_kv["TranSeq"]
    s_collectseqno = t_kv["CollectSeqNo"]

    s_acctno = t_kv["AcctNo"]
    s_acctno1 = t_kv["AcctNo1"]

    -- 机构号
    s_brc = t_kv["Brc"]
    ApmData.replaceField("transaction.branch_code", s_brc == nil and "" or string.trim(s_brc))

    -- 柜员号
    s_teller = t_kv["Teller"]
    ApmData.replaceField("transaction.teller_code", s_teller == nil and "" or string.trim(s_teller))

    -- 交易号
--    ApmData.replaceField("transaction.code", s_tran_code == nil and "" or s_tran_code)

    -- 交易名
    s_type_name = t_kv["TranName"]
    ApmData.replaceField("transaction.type_code", s_type_name == nil and "未知" or string.trim(s_type_name))
    ApmData.replaceField("transaction.type_name", s_type_name == nil and "未知" or string.trim(s_type_name))
    --    ApmData.replaceField("transaction.title", s_type_name == nil and "未知" or string.trim(s_type_name))

    -- 交易渠道
    s_channel_id = t_kv["ChannelId"]
    if s_channel_id == nil then
        s_channel_id = "未知"
    else
        local s_channel_id_in_arr = arr_channel_id[s_channel_id];
        if s_channel_id_in_arr == nil then
        else
            s_channel_id = s_channel_id_in_arr
        end
    end
    ApmData.replaceField("transaction.channel_code", s_channel_id)
    ApmData.replaceField("transaction.channel_name", s_channel_id)

    -- 响应代码
    s_rspcode = t_kv["RspCode"]
    if s_rspcode ~= nil then
        s_rspcode = string.trim(s_rspcode);
        if s_rspcode ~= "" then
            --            local i_code = s_rspcode == "000000" and 0 or 1;
            --            ApmData.replaceField("response.code", i_code);
            ApmData.replaceField("response.code_string", s_rspcode);
        end
    end

    -- 响应信息
    s_rspmsg = t_kv["RspMsg"];
    if s_rspmsg ~= nil then
        s_rspmsg = string.trim(s_rspmsg);
        if s_rspmsg ~= "" then
            ApmData.replaceField("response.error_message", s_rspmsg);
        end
    end

    return true;
end

--- main
function post_analysis()
    local ApmData = require("ApmData")
    if ApmData.getL7Proto() ~= 1435 then return end

    local s_em_type = ApmData.getMsgType();
    if s_em_type == nil then return end

    -- 设置交易渠道
    --    local s_src_ip = ApmData.getSrcIp();
    --    if s_src_ip ~= nil then
    --        ApmData.replaceField("transaction.channel_name", s_src_ip);
    --        ApmData.replaceField("transaction.channel_code", s_src_ip);
    --    end

    local s_message, s_message_body, s_tran_code

    if s_em_type == 0 then -- 请求
    --        s_message = ApmData.getField("request.dts.service.arg.1", 1)
    --        if s_message ~= nil then
    --            s_message = string.trim(s_message)
    --            s_message_body, s_tran_code = head_parser(s_message)
    --            parse_request(ApmData, s_message_body, s_tran_code)
    --        end
    elseif s_em_type == 1 then -- 响应
        s_message = ApmData.getField("response.dts.service.return.1", 1)
        if s_message ~= nil then
            s_message_resp = string.trim(s_message)
            s_message_body, s_tran_code = head_parser(s_message_resp)
            parse_response(ApmData, s_message_body, s_tran_code)
            ApmData.replaceField("response.dts.service.return.1", s_message);
        end

        s_message = ApmData.getField("request.dts.service.arg.1", 1)
        if s_message ~= nil then
            s_message_req = string.trim(s_message)
            s_message_body, s_tran_code = head_parser(s_message_req)
            parse_request(ApmData, s_message_body, s_tran_code)
            ApmData.replaceField("request.dts.service.arg.1", s_message);
        end

        ApmData.delFields("response.code");

        if s_seq_no == nil then
            ApmData.replaceField("transaction.code", "")
        elseif s_seq_no == "0" then
            ApmData.replaceField("transaction.code", s_termseq == nil and s_seq_no or s_termseq)
        else
            ApmData.replaceField("transaction.code", string.trim(s_seq_no))
        end

        local s_log_text = ""

        if s_acqserstan ~= nil then
            s_log_text = s_log_text .. "受理流水号:" .. s_acqserstan .. "|"
        end
        if s_billstan ~= nil then
            s_log_text = s_log_text .. "票据流水号:" .. s_billstan .. "|"
        end
        if s_cancelseq ~= nil then
            s_log_text = s_log_text .. "冲正流水号:" .. s_cancelseq .. "|"
        end
        if s_clearserstan ~= nil then
            s_log_text = s_log_text .. "结消流水号:" .. s_clearserstan .. "|"
        end
        if s_ptxnseq ~= nil then
            s_log_text = s_log_text .. "主机流水号:" .. s_ptxnseq .. "|"
        end
        if s_recvstan ~= nil then
            s_log_text = s_log_text .. "来帐流水号:" .. s_recvstan .. "|"
        end
        if s_sendstan ~= nil then
            s_log_text = s_log_text .. "发送流水号:" .. s_sendstan .. "|"
        end
        if s_serstan ~= nil then
            s_log_text = s_log_text .. "网点流水号:" .. s_serstan .. "|"
        end
        if s_telseq ~= nil then
            s_log_text = s_log_text .. "柜员流水号:" .. s_telseq .. "|"
        end
        if s_termseq ~= nil then
            s_log_text = s_log_text .. "终端流水号:" .. s_termseq .. "|"
        end
        if s_devstan ~= nil then
            s_log_text = s_log_text .. "终端交易流水号:" .. s_devstan .. "|"
        end
        if s_srvstan ~= nil then
            s_log_text = s_log_text .. "前置机流水号:" .. s_srvstan .. "|"
        end
        if s_transeq ~= nil then
            s_log_text = s_log_text .. "交易流水号1:" .. s_transeq .. "|"
        end
        if s_collectseqno ~= nil then
            s_log_text = s_log_text .. "交易流水号2:" .. s_collectseqno .. "|"
        end

        local s_log_acctno = "";
        if s_acctno ~= nil and s_acctno1 ~= nil then
            s_log_acctno = s_log_acctno .. "付款人账号:" .. s_acctno .. "|收款人账号:" .. s_acctno1 .. "|"
            ApmData.replaceField("transaction.acctno", s_acctno)
            ApmData.replaceField("transaction.acctno1", s_acctno1)
        elseif s_acctno ~= nil then
            s_log_acctno = s_log_acctno .. "账号:" .. s_acctno .. "|"
            ApmData.replaceField("transaction.acctno", s_acctno)
        end

        logInfo("核心系统(%s->%s) 流水号:%s|%s%s机构号:%s|柜员号:%s|交易号:%s|交易名:%s|交易渠道:%s|返回码:%s|%s",
            parseIp(ApmData.getSrcIp()),
            parseIp(ApmData.getDstIp()),
            s_seq_no,
            s_log_acctno,
            s_log_text,
            s_brc,
            s_teller,
            s_tran_code,
            s_type_name,
            s_channel_id,
            s_rspcode,
            s_rspmsg == nil and "" or s_rspmsg)
        --
        --        if s_seq_no == nil or
        --                s_brc == nil or
        --                s_teller == nil or
        --                s_tran_code == nil or
        --                s_type_name == nil or
        --                s_channel_id == nil or
        --                s_rspcode == nil then
        --            logError("核心系统:REQ:[%s]\nRESP:[%s]", s_message_req, s_message_resp)
        --        end
        --        logError("核心系统:REQ:[%s]\nRESP:[%s]\n\n", s_message_req, s_message_resp)
    end

    return;
end
